package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.AccraditationRecordConstant;
import com.zzyl.dto.BillDto;
import com.zzyl.dto.ContractDto;
import com.zzyl.entity.*;
import com.zzyl.enums.ContractStatusEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.*;
import com.zzyl.service.*;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.ContractVo;
import com.zzyl.vo.RecordVo;
import com.zzyl.vo.RoomVo;
import com.zzyl.vo.retreat.ElderVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 合同 Service 实现类
 */
@Service
public class ContractServiceImpl implements ContractService {

    @Autowired
    private ContractMapper contractMapper;

    @Resource
    private MemberService memberService;

    @Autowired
    private ActFlowCommService actFlowCommService;

    @Autowired
    private CheckInMapper checkInMapper;

    @Autowired
    private AccraditationRecordService accraditationRecordService;

    @Resource
    private ElderService elderService;

    @Autowired
    private ElderMapper elderMapper;

    @Resource
    private NursingTaskService nursingTaskService;

    @Resource
    private BillService billService;

    @Resource
    private CheckInConfigService checkInConfigService;

    @Resource
    private BedService bedService;

    @Resource
    private BalanceMapper balanceMapper;

    @Resource
    private BedMapper bedMapper;

    @Autowired
    private RoomMapper roomMapper;

    /**
     * 根据id查询合同
     * @param id 合同id
     * @return 合同实体类
     */
    @Override
    public ContractVo getById(Long id) {
        Contract contract = contractMapper.selectByPrimaryKey(id);
        return BeanUtil.toBean(contract, ContractVo.class);
    }

    /**
     * 添加合同
     *
     * @param contractDto 合同dto
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void sign(ContractDto contractDto) {
        // 1.更新入住流程状态
        CheckIn checkIn = checkInMapper.selectByPrimaryKey(contractDto.getCheckInId());
        if (ObjectUtil.isNull(checkIn)) {
            throw new RuntimeException("入住信息不存在");
        }
        checkIn.setStatus(CheckIn.Status.FINISHED.getCode());
        checkIn.setFlowStatus(CheckIn.FlowStatus.SIGN.getCode());
        checkInMapper.updateByPrimaryKeySelective(checkIn);
        // 2.更新老人状态
        Elder elder = elderMapper.selectByPrimaryKey(checkIn.getElderId());
        if (ObjectUtil.isNull(elder)) {
            throw new RuntimeException("老人信息不存在");
        }
        elder.setStatus(1);
        elderMapper.updateByPrimaryKeySelective(elder);
        // 3.保存老人余额
        Balance balance = new Balance();
        balance.setElderId(elder.getId());
        balance.setElderName(elder.getName());
        balance.setBedNo(elder.getBedNumber());
        balance.setPrepaidBalance(BigDecimal.valueOf(0));
        balance.setArrearsAmount(BigDecimal.valueOf(0));
        balance.setStatus(0);
        CheckInConfig checkInConfig = checkInConfigService.findCurrentConfigByElderId(elder.getId());
        Optional.ofNullable(checkInConfig).ifPresent(config -> balance.setDepositAmount(config.getDepositAmount()));
        balanceMapper.insert(balance);
        // 4.更新床位状态
        Optional.ofNullable(checkInConfig).ifPresent(config -> {
            String bedNo = config.getBedNo();
            Bed bed = bedMapper.getBedByNum(bedNo);
            if (ObjectUtil.isNotEmpty(bed)) {
                bed.setBedStatus(1);
                bedMapper.updateBed(bed);
            }
        });
        // 5.保存老人合同
        Contract contract = new Contract();
        BeanUtils.copyProperties(contractDto, contract);
        contract.setElderId(elder.getId());
        contract.setElderName(elder.getName());
        contract.setStatus(ContractStatusEnum.PENDING_EFFECTIVE.getOrdinal());
        contractMapper.insert(contract);
        // 6.生成首月账单
        BillDto billDto = new BillDto();
        billDto.setElderId(elder.getId());
        Optional.ofNullable(checkInConfig).ifPresent(config -> billDto.setBillMonth(LocalDateTimeUtil.format(config.getCostStartTime(), "yyyy-MM")));
        billService.createMonthBill(billDto);
        // 7.生成护理任务
        ElderVo elderVo = BeanUtil.toBean(elder, ElderVo.class);
        nursingTaskService.createMonthTask(elderVo, contract.getSignDate(), null);
        // 8.执行任务
        User user = JSONUtil.toBean(UserThreadLocal.getSubject(), User.class);
        actFlowCommService.completeProcess("", contractDto.getTaskId()
                , user.getId().toString(), 1, CheckIn.Status.FINISHED.getCode());
        // 9.保存操作记录
        RecordVo recordVo = getRecordVo(
                checkIn,
                user,
                AccraditationRecordConstant.AUDIT_STATUS_PASS,
                "同意",
                "法务处理-签约办理",
                "",
                null,
                AccraditationRecordConstant.RECORD_HANDLE_TYPE_PROCESSED);
        accraditationRecordService.insert(recordVo);
    }


    /**
     * 获取操作记录数据
     * @param checkIn  入住对象
     * @param user  当前登录用户
     * @param status  审核状态
     * @param option  操作意见
     * @param step    当前步骤
     * @param nextStep   下一步说明
     * @param nextAssignee  下一个审核人
     * @return
     */
    private RecordVo getRecordVo(CheckIn checkIn, User user, Integer status, String option, String step, String nextStep, Long nextAssignee, Integer handleType){
        RecordVo recordVo = new RecordVo();
        recordVo.setId(checkIn.getId());
        recordVo.setType(AccraditationRecordConstant.RECORD_TYPE_CHECK_IN);
        recordVo.setFlowStatus(checkIn.getFlowStatus());
        recordVo.setStatus(status);
        recordVo.setOption(option);
        recordVo.setNextStep(nextStep);
        recordVo.setNextAssignee(nextAssignee);
        recordVo.setUserId(user.getId());
        recordVo.setRealName(user.getRealName());
        recordVo.setHandleType(handleType);
        recordVo.setStep(step);
        return recordVo;
    }

    /**
     * 更新合同
     * @param contractDto 合同dto
     * @return 更新结果
     */
    @Override
    public int update(ContractDto contractDto) {
        Contract contract = new Contract();
        BeanUtils.copyProperties(contractDto, contract);
        return contractMapper.updateByPrimaryKey(contract);
    }

    /**
     * 根据id删除合同
     * @param id 合同id
     * @return 删除结果
     */
    @Override
    public int deleteById(Long id) {
        return contractMapper.deleteByPrimaryKey(id);
    }

    /**
     * 分页查询合同信息
     *
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param contractNo 合同编号
     * @param elderName 老人姓名
     * @param status 合同状态
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 分页结果
     */
    @Override
    public PageResponse<ContractVo> selectByPage(Integer pageNum, Integer pageSize, String contractNo, String elderName,
                                                 Integer status, LocalDateTime startTime, LocalDateTime endTime) {
        PageHelper.startPage(pageNum, pageSize);

        // 通过丙方手机号关联合同
        String phone = null;
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isNotEmpty(userId)) {
            Member byId = memberService.getById(userId);
            if (ObjectUtil.isNotEmpty(byId)) {
                phone = byId.getPhone();
            }
        }
        Page<List<Contract>> page = contractMapper.selectByPage(phone, contractNo, elderName, status, startTime, endTime);
        return PageResponse.of(page, ContractVo.class);
    }

    @Override
    public List<Contract> listAllContracts() {
        return contractMapper.listAllContracts();
    }

    @Override
    public void updateBatchById(List<Contract> updateList) {
        List<Long> collect = updateList.stream().map(Contract::getId).collect(Collectors.toList());
        contractMapper.batchUpdateByPrimaryKeySelective(collect, updateList.get(0).getStatus());
    }

    @Override
    public List<ContractVo> listByMemberPhone(String phone) {
        return contractMapper.listByMemberPhone(phone);
    }
}


